#include "../include/cmd.h"

int ll_command(int peerfd, cmd_t *cmd)
{
    //创建目录流
    DIR* pdir;
    char* currentPath;
    char buff[10240] ={0};
    train_t train;

    if(cmd->argSize == 0)
    {
        //没有多余参数，打印当前目录
        currentPath = ".";
        pdir = opendir(currentPath);
        if(pdir == NULL)
        {
            char msg[] = "opendir error!";
            memset(&train, 0, sizeof(train));
            sprintf(train.buff, "%s\n", msg);
            train.length = strlen(msg);
            send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            exit(1);
        }
    }
    else
    {
        //打开参数数组中的路径目录
        currentPath = cmd->args[0].arg;
        pdir = opendir(currentPath);
        if(pdir == NULL)
        {
            char msg[] = "opendir error!";
            memset(&train, 0, sizeof(train));
            sprintf(train.buff, "%s\n", msg);
            train.length = strlen(msg);
            send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            exit(1);
        }
    }

    //读目录项
    struct dirent* pdirent;
    struct stat state;
    errno = 0;

    //记录目录总大小
    long total_size = 0;

    while((pdirent = readdir(pdir)) != NULL)
    {
        //将路径名和文件名打包
        char* name = pdirent->d_name;
        char pathName[1024] = {0};
        sprintf(pathName, "%s/%s", currentPath, name);

        //显示详细信息
        //完整路径载入state 以获取此文件信息
        int ret = stat(pathName, &state);
        if(ret == -1)
        { 
            char msg[] = "stat error!";
            memset(&train, 0, sizeof(train));
            sprintf(train.buff, "%s\n", msg);
            train.length = strlen(msg);
            send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            exit(1);
        }

        //打印文件类型
        switch(state.st_mode & S_IFMT)
        { 
        case S_IFREG: sprintf(buff, "%s- ", buff); break;
        case S_IFDIR: sprintf(buff, "%sd ", buff); break;
        case S_IFBLK: sprintf(buff, "%sb ", buff); break;
        case S_IFCHR: sprintf(buff, "%sc ", buff); break;
        case S_IFIFO: sprintf(buff, "%sp ", buff); break;
        case S_IFLNK: sprintf(buff, "%sl ", buff); break;
        case S_IFSOCK: sprintf(buff, "%ss ", buff); break;
        default: sprintf(buff, "%s? ", buff); break;
        }

        int execute_flag = 0;
        //打印文件权限 用户、小组、其他
        for(int i = 0; i < 3; i++)
        {
            //先偏移再判断相应权限
            int mode = (state.st_mode >> 3 * (2 - i)) & 0x7;

            switch(mode)
            {
            case 0: sprintf(buff,"%s--- ",buff); break;
            case 1: sprintf(buff,"%s--x ",buff); break;
            case 2: sprintf(buff,"%s-w- ",buff); break;
            case 3: sprintf(buff,"%s-wx ",buff); break;
            case 4: sprintf(buff,"%sr-- ",buff); break;
            case 5: sprintf(buff,"%sr-x ",buff); break;
            case 6: sprintf(buff,"%srw- ",buff); break;
            case 7: sprintf(buff,"%srwx ",buff); break;
            }

            if(mode == 1 || mode == 3 || mode == 5 || mode == 7)
            {
                execute_flag = 1;
            }
        }

        //打印硬链接数，用户名，组名，文件大小
        //获取包含用户名和组名的结构体
        struct passwd* pwd = getpwuid(state.st_uid);
        if(pwd == NULL)
        { 
            char msg[] = "getpwuid error!";
            memset(&train, 0, sizeof(train));
            sprintf(train.buff, "%s\n", msg);
            train.length = strlen(msg);
            send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            exit(1);
        }

        struct group* grp = getgrgid(state.st_gid);
        if(grp == NULL)
        { 
            char msg[] = "getgrgid error!";
            memset(&train, 0, sizeof(train));
            sprintf(train.buff, "%s\n", msg);
            train.length = strlen(msg);
            send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            exit(1);
        }


        sprintf(buff,"%s %4ld %8s %8s %20ld ",buff,
                state.st_nlink, pwd->pw_name, grp-> gr_name, state.st_size);

        //打印最近访问的年月日时分秒
        struct tm* ptime = localtime(&state.st_atime);
        if(ptime == NULL)
        {
            char msg[] = "localtime error!";
            memset(&train, 0, sizeof(train));
            sprintf(train.buff, "%s\n", msg);
            train.length = strlen(msg);
            send(peerfd, &train, 4 + train.length, MSG_WAITALL);
            exit(1);
        }


        sprintf(buff,"%s %d/%.2d/%.2d  %.2d:%.2d:%.2d ",buff,
                ptime->tm_year + 1900, ptime->tm_mon + 1, ptime->tm_mday,
                ptime->tm_hour, ptime->tm_min, ptime->tm_sec);

        //打印文件名
        if(name[0] == '.')
        {
            sprintf(buff,"%s %s", buff, name);
            sprintf(buff,"%s/\n",buff);
        }
        //如果是目录文件，则打印时，为青蓝色，便于cd操作
        else if((state.st_mode & S_IFMT) == S_IFDIR)
        {
            sprintf(buff,"%s %s\n", buff, name);
        }
        //如果是可执行文件，打印为绿色 （常规文件 且 可执行）
        else if((state.st_mode & S_IFMT) == S_IFREG
                && execute_flag == 1)
        {
            sprintf(buff,"%s %s",buff, name);
            sprintf(buff,"%s*\n",buff);
        }
        //其他类型文件，直接打印文件名
        else
        {
            sprintf(buff,"%s %s\n", buff,name);
        }

        //总大小加上该文件大小
        total_size += state.st_size;
    }

    //错误处理
    if(errno != 0)
    {
        perror("readdir");
        exit(1);
    }

    //打印目录所有文件总大小
    sprintf(buff,"%stotal size = %ld KB\n",buff, total_size / 1024);

    //关闭目录流
    closedir(pdir);

    //把内容buff发送到客户端
    int length = strlen(buff);
    int ret =send(peerfd, &length, 4, MSG_WAITALL);
    printf("send length : %d\n", length);
    ret =send(peerfd, buff, length, MSG_WAITALL);
        if(ret == 0){
            printf("connect broken\n");
            close(peerfd);
        }else if(ret == -1){
            perror("send");
            exit(1);
        }
    //服务端反馈
    puts("ll_command execute success!");
    return 1;
}
